/*
 * @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @Date: 2023-10-10 20:56:31
 * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @LastEditTime: 2023-11-27 18:15:00
 * @FilePath: /logsystem/logs/test.cpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include "../logs/zbtlog.hpp"
#include <unistd.h>

/*扩展一个以时间作为滚动切换类型的日志落地模块
    1.一时间进行文件滚动，实际上是以时间段进行滚动
        实现思想：取模时间段大小，可以得到当前时间段是第几个时间段
        每次以当前系统时间取模，判断与当前文件的时间段是否一致，不一致则代表不是同一个时间段

*/
enum class TimeGap{
    GAP_SECOND,
    GAP_MINUTE,
    GAP_HOUR,
    GAP_DAY,
};
 class RollByTimeSink :public zbtlog::LogSink{
        public:
            //构造时传入文件名，并打开文件，将操作句柄管理起来
            RollByTimeSink(const std::string &basename, TimeGap gap_type):_basename(basename){   
                switch (gap_type){
                    case TimeGap::GAP_SECOND: _gap_size = 1; break;
                    case TimeGap::GAP_MINUTE: _gap_size = 60; break;
                    case TimeGap::GAP_HOUR: _gap_size = 3600; break;
                    case TimeGap::GAP_DAY: _gap_size = 3600 * 24; break;
                }
                _cur_cnt = _gap_size == 1 ?zbtlog::util::Date::now() : zbtlog::util::Date::now() % _gap_size;//获取当前是第几个时间段
                std::string filename = createNewFile();
                zbtlog::util::File::createDirectory(zbtlog::util::File::path(filename));
                _ofs.open(filename, std::ios::binary | std::ios::app);
                assert(_ofs.is_open());
                
            }
            //将日志写入到标准输出，判断当前时间是否为当前文件的时间段，不是则切换文件
            void log(const char* data, size_t len){
                time_t cur = zbtlog::util::Date::now();
                if((cur % _gap_size) != _cur_cnt){
                    _ofs.close();
                    std::string filename = createNewFile();
                    _ofs.open(filename, std::ios::binary | std::ios::app);
                    assert(_ofs.is_open());
                }
                _ofs.write(data, len);
                assert(_ofs.good());
            }
        private:
            std::string createNewFile(){
                time_t t = zbtlog::util::Date::now();
                struct tm lt;
                localtime_r(&t, &lt);
                std::stringstream filename;
                filename << _basename;
                filename << lt.tm_year + 1900;
                filename << lt.tm_mon + 1;
                filename << lt.tm_mday;
                filename << lt.tm_hour;
                filename << lt.tm_min;
                filename << lt.tm_sec;
                filename << ".log";
                return filename.str();
            }
            std::string _basename;
            std::ofstream _ofs;
            size_t _cur_cnt;//当前为第几个时间段
            size_t _gap_size;//时间段大小
    };
    
void test_log(const std::string &name) {
    DEBUG("%s", "测试开始");
    zbtlog::Logger::ptr logger = zbtlog::LoggerMannger::getInstance().getLogger(name);
    logger->debug("%s", "测试日志");
    logger->info("%s", "测试日志");
    logger->warn("%s", "测试日志");
    logger->error("%s", "测试日志");
    logger->fatal("%s", "测试日志");
    size_t count = 0;
    while(count < 200000){
        logger->fatal("测试日志-%d", count++);
    }    
    INFO("%s", "测试完毕");
}

int main()
{
    //读取文件数据，一点一点写入缓冲区，最终将缓冲区数据写入文件，判断生成的新文件与源文件是否一致
    // std::ifstream ifs("./logfile/class.log", std::ios::in | std::ios::binary);
    // if(ifs.is_open() == false) { std::cout << "open faild!\n"; return -1;}
    // ifs.seekg(0, std::ios::end);//读写位置跳转到文件末尾
    // size_t fsize = ifs.tellg();//获取当前读写位置相对于起始位置的偏移量
    // ifs.seekg(0, std::ios::beg);//重新跳转到起始位置
    // std::string body;
    // body.resize(fsize);
    // ifs.read(&body[0], fsize);
    // if (ifs.good() == false) { std::cout << "read error\n"; return -1;}
    // ifs.close();

    // std::cout << fsize << std::endl;
    // zbtlog::Buffer buffer;
    // for(int i = 0; i < body.size(); i++) {
    //     buffer.push(&body[i], 1);
    // }
    // std::cout << buffer.readAbleSize() << std::endl;
    
    // std::ofstream ofs("./logfile/tmp.log", std::ios::binary);
    // //ofs.write(buffer.begin(), buffer.readAbleSize());
    // size_t rsize = buffer.readAbleSize();
    // for(int i = 0; i < rsize; i++) {
    //     ofs.write(buffer.begin(), 1);
    //     if(ofs.good() == false) {std::cout << "write error!\n"; return -1;}
    //     buffer.moveReader(1);
    // }
    // if(ofs.good() == false) {std::cout << "write error!\n"; return -1;}
    // ofs.close();

    std::unique_ptr<zbtlog::LoggerBuilder> builder(new zbtlog::GloballLoggerBuilder());
    builder->buildLoggerName("async_logger");
    builder->buildLoggerLevel(zbtlog::LogLevel::value::WARN);
    builder->buildFormatter("[%c][%f:%l]%m%n");
    builder->buildLoggerType(zbtlog::LoggerType::LOGGER_ASYNC);
    //极限性能测试时使用的
    //builder->buildEnableUnSafeAsync();
    
    builder->buildSink<RollByTimeSink>("./logfile/roll-async-by-time", TimeGap::GAP_SECOND);
    zbtlog::Logger::ptr logger = builder->build();
    size_t cur = zbtlog::util::Date::now();
    while(zbtlog::util::Date::now() < cur + 5) {
        logger->fatal("这是一条测试日志");
        usleep(1000);
    }
    

    // zbtlog::LogMsg msg(zbtlog::LogLevel::value::IFNO, 52, "main.c", "root", "格式化功能测试...");
    // zbtlog::Formatter fmt;
    // std::string str = fmt.format(msg);
    // // zbtlog::LogSink::ptr stdout_lsp = zbtlog::SinkFactory::create<zbtlog::StdoutSink>();
    // // zbtlog::LogSink::ptr file_lsp = zbtlog::SinkFactory::create<zbtlog::FileSink>("./logfile/class.log");
    // // zbtlog::LogSink::ptr roll_lsp = zbtlog::SinkFactory::create<zbtlog::RollSinkBySize>("./logfile/roll--", 1024*1024);

    // zbtlog::LogSink::ptr time_lsp = zbtlog::SinkFactory::create<RollByTimeSink>("./logfile/roll--", TimeGap::GAP_SECOND);
    // time_t old = zbtlog::util::Date::now();
    // while(zbtlog::util::Date::now() < old + 5) {
    //     time_lsp->log(str.c_str(), str.size());
    //     usleep(1000);
    // }
    // stdout_lsp->log(str.c_str(), str.size());
    // file_lsp->log(str.c_str(), str.size());
    // size_t cursize = 0;
    // size_t cnt = 0;
    // while(cursize < 1024 * 1024 * 10){
    //     std::string tmp = str + std::to_string(cnt++);
    //     roll_lsp->log(tmp.c_str(), tmp.size());
    //     cursize += tmp.size();
    // }

    // std::cout << zbtlog::LogLevel::tostring(zbtlog::LogLevel::value::DEBUG) << std::endl;
    // std::cout << zbtlog::LogLevel::tostring(zbtlog::LogLevel::value::IFNO) << std::endl;
    // std::cout << zbtlog::LogLevel::tostring(zbtlog::LogLevel::value::WARN) << std::endl;
    // std::cout << zbtlog::LogLevel::tostring(zbtlog::LogLevel::value::ERROR) << std::endl;
    // std::cout << zbtlog::LogLevel::tostring(zbtlog::LogLevel::value::FATAL) << std::endl;
    // std::cout << zbtlog::LogLevel::tostring(zbtlog::LogLevel::value::OFF) << std::endl;

    // std::cout << zbtlog::util::Date::getTime() << std::endl;
    // std::string pathname = "./adc/bcd/arr.txt";
    // zbtlog::util::File::createDirectory(zbtlog::util::File::path(pathname));
    return 0;
}
